// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-01-01 // Contains ... namespace LargoEditor.Abstract { using LargoBase.Abstract; using LargoBase.Enums; using LargoBase.Localization; using LargoBase.Midi; using LargoBase.Music; using LargoKernel; using LargoKernel.Blocks; using LargoKernel.Board; using LargoKernel.Composer; using LargoKernel.Patterns; using LargoModels; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.IO; using System.Linq; /// /// Musical Editor. /// public sealed class BlockEditor { #region Fields //// Prepared for the future /// /// Max Editor Lines. /// //// private const int MaxEditorLines = 250; /// /// Max Editor Bars. /// //// private const int MaxEditorBars = 2500; #endregion #region Constructors /// /// Initializes a new instance of the class. /// public BlockEditor() { this.MusicalSelection = new MusicalSelection(); this.EditorContent = EditorContent.NumberOfTones; this.EditorColor = EditorColor.RhythmicDensity; } #endregion #region Public static properties /// /// Gets or sets the lastly edited musical block. /// /// Property description. public static MusicalBlock LastlyEditedMusicalBlock { get; set; } /// /// Gets or sets the lastly edited block model. /// /// Property description. public static BlockModel LastlyEditedBlockModel { get; set; } #endregion #region Public properties (Editor selection) /// /// Gets or sets Largo File Path. /// /// /// Property description. /// public string LargoFilePath { get; set; } /// /// Gets or sets a value indicating whether this instance has changes. /// /// /// true if this instance has changes; otherwise, false. /// public bool HasChanges { get; set; } /// /// Gets a value indicating whether selection. /// /// Property description. public bool HasSelection => MusicalSelection?.Points != null && this.MusicalSelection.Points.Any(); /// /// Gets the selection. /// /// Property description. public MusicalSelection MusicalSelection { get; } /// /// Gets the selected elements. /// /// Property description. public IList SelectedElements { get { if (!this.HasSelection) { return null; } var list = new List(); list.AddRange(this.Block.Body.GetSelectedElements(this.MusicalSelection)); return list; } } #endregion #region Public Properties /// /// Gets or sets Musical Block Model. /// /// /// Property description. /// public MusicalBlock Block { get; set; } /// /// Gets or sets Musical Block Model. /// /// /// Property description. /// public BlockModel BlockModel { get; set; } /// /// Gets the name of the block model. /// /// /// The name of the block model. /// /// Not Implemented public string BlockModelName { get { if (this.BlockModel != null) { return this.BlockModel.FileAndName; //// givenBlock.FullName; } return string.Empty; } } /// /// Gets the display name. /// /// /// The display name. /// /// Not Implemented Exception public string DisplayName { get { if (this.Block != null) { return this.Block.NumberNameAndLength; } if (this.BlockModel != null) { return this.BlockModel.NumberNameAndLength; } return string.Empty; } } /// /// Gets or sets the content of the editor. /// /// /// The content of the editor. /// public EditorContent EditorContent { get; set; } /// /// Gets or sets the color of the editor. /// /// /// The color of the editor. /// public EditorColor EditorColor { get; set; } /// /// Gets or sets the name. /// /// /// The name of edited document. /// public string Name { get; set; } /// /// Gets or sets the description. /// /// /// The description. /// public string Description { get; set; } /// /// Gets or sets a value indicating whether [play on click]. /// /// /// True if [play on click]; otherwise, false. /// public bool PlayOnClick { get; set; } /// /// Gets or sets a value indicating whether [synchronize motives]. /// /// /// true if [synchronize motives]; otherwise, false. /// public bool SynchronizeMotives { get; set; } /// /// Gets or sets a value indicating whether [hide mute tracks]. /// /// /// true if [hide mute tracks]; otherwise, false. /// public bool HideMuteTracks { get; set; } /// /// Gets the fixed tracks. /// /// Returns value. public IList GetFixedTracks { get { List tracks = new List(); for (byte lineIndex = 0; lineIndex < this.Block.Header.NumberOfTracks; lineIndex++) { var track = this.GetTrack(lineIndex); if (track != null && track.Status.Purpose == TrackPurpose.Fixed) { //// track.HasTemplate tracks.Add(track); } } return tracks; } } /// /// Gets all tracks for composition. /// /// Returns value. public IList GetAllTracksForComposition { get { List tracks = new List(); //// if (composeAll) { mblock.LoadTracksFromModel(blockModel); return; } for (byte lineIndex = 0; lineIndex < this.Block.Header.NumberOfTracks; lineIndex++) { var track = this.GetTrack(lineIndex); if (track == null || track.Status.Purpose == TrackPurpose.Mute || track.Status.Purpose == TrackPurpose.None) { continue; } //// (composeAllTracks && eline.IsImported) if (track.Status.Purpose == TrackPurpose.Fixed) { //// Add original imported track tracks.Add(track); } // ReSharper disable once InvertIf if (track.Status.Purpose == TrackPurpose.Composed) { track.Reset(); track.Status.MelodicVariety = new MusicalVariety(MusicalSetup.Singleton); //// 2016/10 newtrack.Status.PlannedTones = new MusicalToneCollection(); //// track.Status.HarmonicModalization = MusicalSetup.Singleton.HarmonicModalization; //// LineType = MusicalLineType.Melodic, //// Purpose = TrackPurpose.Composed, //// Channel = track.Channel //// 2016 if (eline.Channel != null) { newtrack.Status.Channel = (MidiChannel)eline.Channel; } tracks.Add(track); } } return tracks; } } #endregion #region Private properties #endregion #region Factory methods #endregion #region Public methods - Loader /// /// Loads the block. /// /// The given block. public void LoadBlock(MusicalBlock givenBlock) { Contract.Requires(givenBlock != null); //// && givenBlock.Strip == null if (givenBlock.Body == null) { return; } this.Name = this.BlockModelName; this.Block = givenBlock; BlockEditor.LastlyEditedMusicalBlock = givenBlock; //// this.LoadTracks(this.Block.Strip); //// this.LoadBars(this.Block.Body); if (this.Block.ContainsMusic) { this.Block.Body.SetStatusFromMusic(); } this.Block.Body.DetermineOriginalElements(); BlockEditor.LastlyEditedBlockModel = this.BlockModel; } #endregion #region Public methods - Composition /// /// Composes the music. /// /// Returns value. public MusicalBundle ComposeMusic() { var currentBlock = this.Block; //// blockModel.SourceMusicalBlock var mheader = (MusicalHeader)currentBlock.Header.Clone(); MusicalContext context = new MusicalContext(MusicalSetup.Singleton, mheader); var composedBlock = new MusicalBlock { //// Number = currentBlock.Number, Header = mheader, Strip = new MusicalStrip(context) }; ProcessLogger.Singleton.SendLogEvent(currentBlock.Header.Name, LocalizedMusic.String("Initialization..."), 0); var tracks = this.GetAllTracksForComposition; //// GetAllTracks(false); composedBlock.Strip.SetTracks(tracks); composedBlock.Header.NumberOfTracks = tracks.Count; composedBlock.ConvertStripToBody(true); //// Have to be --- set status from editor !!!!!!!!!! //// 2016/03 !!!!!!!!!!!!! //// var blockModel = this.Block.ExtractMusicalBlockModel(); ///// composedBlock.SetMusicalStatus(blockModel); var blockStatus = new BlockStatus(currentBlock); composedBlock.SetBlockStatus(blockStatus); //// TEMPO 2017/01 ?!? //// composedBlock.SetTempoEvents(blockModel.BlockChanges.TempoChanges); var tevents = new List(); int deltatime = 0; var h = composedBlock.Header; var barmididuration = MusicalProperties.BarMidiDuration(h.System.RhythmicOrder, h.Metric.MetricBeat, h.Metric.MetricGround, h.Division); foreach (var bar in composedBlock.Body.Bars) { if (bar.Status.TempoNumber > 0) { var tevent = new MetaTempo(0, 100) { StartTime = deltatime, Tempo = bar.Status.TempoNumber }; tevents.Add(tevent); deltatime += barmididuration; } } if (tevents.Count > 0) { composedBlock.Body.TempoEvents = tevents; //// !?!?!? do not work } //// Main compositional method. composedBlock.Body.ComposeMusic(); ProcessLogger.Singleton.SendLogEvent(currentBlock.Header.Name, LocalizedMusic.String("Finalization..."), 0); composedBlock.Strip.WriteBody(composedBlock.Body); composedBlock.Strip.CorrectOctaves(); var filename = currentBlock.FullName; int variant = 0; while (File.Exists(filename)) { variant++; filename = currentBlock.FullName + variant.ToString(); } var composedFile = MusicalBundle.GetEnvelopeOfBlock(composedBlock, filename); return composedFile; } #endregion /// /// Shifts the line octaves. /// /// The number of octaves. public void ShiftOctavesInSelection(int numberOfOctaves) { //// int lineIndex, ///// var elements = this.BlockEditor.SelectedLineElements(eline.LineIndex); var elements = this.SelectedElements; //// var elements = this.SelectedLineElements(lineIndex); //// var elements = this.ElementsOfLine(lineIndex); if (elements == null) { return; } foreach (var element in elements.Where(element => element != null)) { element.ShiftOctave(numberOfOctaves); } } /// /// Selected line elements. /// /// Index of the given line. /// Returns value. public IList SelectedLineElements(int givenLineIndex) { if (!this.HasSelection) { return null; } var list = new List(); list.AddRange(this.Block.Body.GetSelectedElements(this.MusicalSelection, givenLineIndex)); return list; } #region Orchestration /// /// Orchestrate By Model. /// /// The given style. public void OrchestrateBy(MusicalOrchestration givenStyle) { if (givenStyle == null || this.Block == null) { return; } this.Block.Orchestration = new MusicalOrchestration(this.Block); givenStyle.OrchestrateMusicalBlock(this.Block); } #endregion #region Tracks /// /// Gets all tracks. /// /// if set to true [include tones]. /// Returns value. public IList GetAllTracks(bool includeTones) { List tracks = new List(); for (byte lineIndex = 0; lineIndex < this.Block.Header.NumberOfTracks; lineIndex++) { var track = this.GetTrack(lineIndex); if (track != null) { var rtrack = includeTones ? track : track.Clone(false); rtrack.Status.MelodicVariety = new MusicalVariety(MusicalSetup.Singleton); //// 2016/10 rtrack.Status.PlannedTones = new MusicalToneCollection(); tracks.Add(rtrack); } } return tracks; } #endregion #region Get bars and lines /// /// Gets the bar. /// /// The given bar number. /// Returns value. public MusicalBar GetBar(int givenBarNumber) { return this.Block.Body.GetBar(givenBarNumber); } /// /// Gets the line. /// /// Index of the given line. /// /// Returns value. /// public MusicalTrack GetTrack(int givenLineIndex) { var track = this.Block.Strip.GetTrack(givenLineIndex); return track; } #endregion #region Rhythmic /// /// Rhythmic of harmony. /// /// Returns value. [UsedImplicitly] public IList RhythmicOfHarmony() { var structs = new List(); // ReSharper disable once LoopCanBeConvertedToQuery foreach (var bar1 in this.Block.Body.Bars.Where(bar1 => bar1 != null)) { if (bar1.Status.HarmonicBar == null) { continue; } var rstr = bar1.Status.HarmonicBar.RhythmicStructure; //// Clone? structs.Add(rstr); } return structs; } /// /// Reorders the line rhythmic. /// /// The line number. /// The block model. public void SetRandomRhythm(int lineIndex, BlockModel blockModel) { Contract.Requires(blockModel != null); var elements = this.Block.Body.ElementsOfLine(lineIndex); var master = new ElementMaster(elements); var rstructures = blockModel.Core.RhythmicCore.RhythmicStructuresOfMotives; master.SetRandomRhythm(rstructures); } #endregion #region Reorder line properties /// /// Reorders the line rhythmic. /// /// The line number. public void ReorderLineRhythmic(int lineIndex) { var elements = this.Block.Body.ElementsOfLine(lineIndex); var master = new ElementMaster(elements); master.ReorderRhythmic(); } /// /// Reorders the line rhythmic. /// /// The line number. public void ReorderLineMelodic(int lineIndex) { var elements = this.Block.Body.ElementsOfLine(lineIndex); //// var musicalEditorElements = elements as IList ?? elements.ToList(); var master = new ElementMaster(elements); master.ReorderMelodic(); } /// /// Reorders the line rhythmic. /// public void ReorderLineHarmonic() { foreach (var bar1 in this.Block.Body.Bars) { if (bar1?.Status.HarmonicBar == null) { continue; } var bar1c = bar1; foreach (var bar2 in this.Block.Body.Bars.Where(bar2 => bar2.Status.HarmonicBar != null && bar2.BarNumber > bar1c.BarNumber).Where(bar2 => MathSupport.RandomNatural(10) < 3)) { bar1.SwapHarmonyWith(bar2); } } } #endregion } }